package day27.homework;

import java.util.Random;

/**
*使用多线程实现龟兔赛跑游戏。
*1. 可以使用随机数取得0~1之间的随机数模拟比赛进程 
*2. 如果随机数在0~0.3之间代表兔子开始跑,每次跑2米。如果随机数在0.3~1之间代表乌龟开始跑，每次跑1米 
*3. 总距离为100米，先跑完100米者为胜利者，输出赛跑过程及谁取得冠军
 */
public class hw11 {
    // 定义比赛总距离为10米（注释中写的是100米，但实际代码是10米）
    // 使用final关键字确保该值不会被修改，static表示这是类级别的常量
    private static final int TOTAL_DISTANCE = 10;
    // 使用volatile关键字确保多线程间的可见性，当一个线程修改了这个变量的值，
    // 其他线程能立即看到修改后的值。用于标记比赛是否已经结束
    private static volatile boolean raceFinished = false;
    // 定义一个对象锁，用于同步代码块，确保只有一个线程能修改raceFinished状态
    // 使用static确保所有线程共享同一个锁对象，避免不同锁导致的同步问题
    private static final Object lock = new Object();
    
    public static void main(String[] args) throws InterruptedException {
        // 打印比赛基本信息，向用户说明比赛规则
        System.out.println("龟兔赛跑比赛总距离: " + TOTAL_DISTANCE + "米");
        System.out.println("兔子每次跑2米，乌龟每次跑1米");
        System.out.println("随机数0~0.3兔子跑，0.3~1乌龟跑");
        
        // 创建兔子线程：使用Lambda表达式定义线程执行逻辑
        // 参数说明：名字为"兔子"，每次跑2米，随机数范围0~0.3时行动
        Thread rabbit = new Thread(() -> race("兔子", 2, 0, 0.3));
        // 创建乌龟线程：使用Lambda表达式定义线程执行逻辑
        // 参数说明：名字为"乌龟"，每次跑1米，随机数范围0.3~1.0时行动
        Thread turtle = new Thread(() -> race("乌龟", 1, 0.3, 1.0));
        
        // 启动两个线程，开始比赛，此时两个线程将并发执行
        rabbit.start();
        turtle.start();
        
        // 使用join()方法让主线程等待两个子线程执行完毕
        // 这样可以确保在所有参赛者都完成比赛后再输出"比赛结束"
        rabbit.join();
        turtle.join();
        
        // 所有线程执行完毕，打印比赛结束信息
        System.out.println("比赛结束");
    }
    
    /**
     * 比赛核心逻辑方法，每个参赛者（兔子或乌龟）都会在独立的线程中执行此方法
     * @param name 参赛者名称（兔子或乌龟）
     * @param speed 每次前进的距离
     * @param min 随机数下限（包含），用于判断该参赛者是否可以行动
     * @param max 随机数上限（不包含），用于判断该参赛者是否可以行动
     */
    private static void race(String name, int speed, double min, double max) {
        // 当前已跑距离，每个线程都有自己的局部变量，互不干扰
        // 这确保了每个参赛者的进度是独立计算的
        int distance = 0;
        // 创建随机数生成器，用于生成0-1之间的随机数来决定参赛者是否可以前进
        Random random = new Random();
        
        // 比赛循环：当未到达终点且比赛未结束时继续
        // 这个条件确保了即使一个参赛者到达终点，另一个参赛者也会停止比赛
        while (distance < TOTAL_DISTANCE && !raceFinished) {
            // 生成0~1之间的随机数，用于决定当前参赛者是否可以前进
            double rand = random.nextDouble();
            
            // 判断随机数是否在指定范围内，决定是否可以前进
            // 例如兔子的范围是[0, 0.3)，乌龟的范围是[0.3, 1.0)
            if (rand >= min && rand < max) {
                // 前进指定距离，根据参赛者不同，speed也不同（兔子2米，乌龟1米）
                distance += speed;
                // 防止超过终点线，确保不会超过总距离
                if (distance > TOTAL_DISTANCE) distance = TOTAL_DISTANCE;
                
                // 打印当前进度，显示参赛者的实时位置
                System.out.println(name + "跑了" + distance + "米");
                
                // 判断是否到达终点且还未宣布比赛结束
                // 这是决定冠军的关键逻辑
                if (distance >= TOTAL_DISTANCE && !raceFinished) {
                    // 使用同步代码块确保线程安全，防止两个线程同时判断为胜利者
                    // synchronized关键字确保同一时间只有一个线程能执行这里的代码
                    synchronized (lock) {
                        // 再次检查比赛是否已经结束（双重检查锁定模式）
                        // 因为在等待获取锁的过程中，另一个线程可能已经结束了比赛
                        if (!raceFinished) {
                            // 宣布比赛结束，当前线程获胜
                            // 修改volatile变量raceFinished，使所有线程都能立即看到变化
                            raceFinished = true;
                            System.out.println(name + "获得冠军!");
                        }
                    }
                }
            }
            
            // 线程休眠100毫秒，控制比赛节奏，避免比赛过程过快
            // 同时也模拟了现实比赛中选手需要休息的情况
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 如果线程在sleep期间被中断，恢复中断状态
                // 这是处理InterruptedException的最佳实践
                Thread.currentThread().interrupt();
            }
        }
    }
}